#import "PinNoteManager.h"

// Shared instance of PinNoteManager
static PinNoteManager* sharedPinNoteManager = nil;

/**
 * A PinNoteManager is an object representing a tool for managing 
 * the interactive placement, editing, and removal of the 
 * user-defined pin notes.
 * 
 * Conforms to the TouchableWindowDelegate protocol.
 *
 * @author      James Lin
 * @version     1.3.7
 * @since       1.0.4
 * @see         TouchableWindowDelegate
 * @see         PinNoteViewerDelegate
 */
@implementation PinNoteManager

@synthesize pinTitle;
@synthesize pinDesc;

/**
 * Retrieve the shared instance of the pin note manager.
 *
 * @return  the shared instance of PinNoteManager
 */
+ (PinNoteManager*)sharedPinNoteManager {
	@synchronized(self) {
		if (sharedPinNoteManager == nil) {
			sharedPinNoteManager = [[PinNoteManager alloc] init];
		}
		return sharedPinNoteManager;
	}
}

/**
 * Allocate the pin note manager.
 *
 * @return  the newly allocated shared instance of PinNoteManager
 */
+ (id) alloc {
	@synchronized(self) {
		sharedPinNoteManager = [super alloc];
		return sharedPinNoteManager;
	}
}

/**
 * Retrieve a copy of the pin note manager.
 *
 * @return  the shared instance of PinNoteManager
 */
+ (id) copy {
	@synchronized(self) {
		return sharedPinNoteManager;
	}
}

/**
 * Initialize the shared instance of the pin note manager.
 *
 * @return  the initialized pin note manager
 */
- (id)init {
	if (self = [super init]) {
		toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(-VIEW_WIDTH, VIEW_HEIGHT-44, VIEW_WIDTH, 44)];
		toolbar.barStyle = UIBarStyleBlack;
		
		relocationToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(-VIEW_WIDTH, VIEW_HEIGHT-44, VIEW_WIDTH, 44)];
		relocationToolbar.barStyle = UIBarStyleBlack;
		
		relocationModeEnabled = NO;
	}
	return self;
}

/**
 * Activate the map pin note tools.
 *
 * @param theDelegate  the delegate handling pin note events
 */
- (void)activateWithDelegate:(id<PinNoteManagerDelegate>)theDelegate {
	// Check for conflicting toolbars
	if (relocationModeEnabled) {
		[delegate toggleVisibilityOfPinNote:currentPinNote];
		[delegate removePinNotes];
		[self performSelector:@selector(deactivateRelocationMode)];
	}
	
	delegate = theDelegate;
	
	// Reset the cached pin note details
	if (pinTitle) {
		[pinTitle release], pinTitle = nil;
	}
	if (pinDesc) {
		[pinDesc release], pinDesc = nil;
	}
	
	if (!isActive) {
		isActive = YES;
		placePinModeEnabled = NO;
		currentPinNote = nil;
		
		[PinNoteViewer sharedPinNoteViewer].pinTitle = @"";
		[PinNoteViewer sharedPinNoteViewer].pinDesc = @"";
		
		// Create the toolbar buttons
		UIBarButtonItem* showAllButton;
		showAllButton = [[UIBarButtonItem alloc] initWithTitle:@"Show All Pins" 
														 style:UIBarButtonItemStyleBordered 
														target:self
														action:@selector(showAllPins)];
		addButton = [[UIBarButtonItem alloc] initWithTitle:@"Add New Pin" 
													 style:UIBarButtonItemStyleBordered
													target:self 
													action:@selector(activateAddMode)];
		UIBarButtonItem* doneButton;
		doneButton = [[UIBarButtonItem alloc] initWithTitle:@"Done" 
													  style:UIBarButtonItemStyleDone
													 target:self 
													 action:@selector(deactivate)];
		UIBarButtonItem* spacer;
		spacer = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
															   target:nil
															   action:nil];
		
		// Add the buttons to the toolbar
		NSArray* buttons = [NSArray arrayWithObjects:showAllButton, addButton, spacer, doneButton, nil];
		[toolbar setItems:buttons animated:NO];
		
		[[delegate getViewController].view addSubview:toolbar];
		
		// Animate the general toolbar into visibility
		[UIView beginAnimations:nil context:@"toolbar"];
		[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
		[UIView setAnimationDuration:0.2];
		[toolbar setFrame:CGRectMake(0, VIEW_HEIGHT-44, VIEW_WIDTH, 44)];
		[UIView commitAnimations];
		
		[showAllButton release];
		[doneButton release];
		[spacer release];
	}
}

/**
 * Helper method to enable placement of a pin note on the map.
 *
 * @param flag  whether the pin to place is new
 */
- (void)activatePlacePinNew:(BOOL)flag {
	if (flag) {
		placePinModeEnabled = YES;
		[GraphicsUtilities showPrompt:@"Place your pin on the map." 
							   inView:[delegate getViewController].view 
							withColor:nil];
	} else {
		placePinModeEnabled = YES;
		[GraphicsUtilities showPrompt:@"Tap to readjust position of pin." 
							   inView:[delegate getViewController].view 
							withColor:nil];
	}
}

/**
 * Helper method to disable placement of a pin note on the map.
 */
- (void)deactivatePlacePin {
	placePinModeEnabled = NO;
	[GraphicsUtilities hidePromptAnimated:YES];
}

/**
 * Deactive the map pin note tools.
 */
- (void)deactivate {
	if (placePinModeEnabled) {
		[delegate savePinNotes];
	}
	
	// Reset the cached pin note details
	if (pinTitle) {
		[pinTitle release], pinTitle = nil;
	}
	if (pinDesc) {
		[pinDesc release], pinDesc = nil;
	}
	
	[PinNoteViewer sharedPinNoteViewer].pinTitle = @"";
	[PinNoteViewer sharedPinNoteViewer].pinDesc = @"";
	
	isActive = NO;
	[self deactivatePlacePin];
	
	// Animate the general toolbar out of visibility
	[UIView beginAnimations:nil context:@"toolbar"];
	[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
	[UIView setAnimationDuration:0.3];
	[toolbar setFrame:CGRectMake(-VIEW_WIDTH, VIEW_HEIGHT-44, VIEW_WIDTH, 44)];
	[UIView commitAnimations];
	
	// Refresh the active pin notes on the map (workaround to current unwanted behaviour)
	[delegate refreshPinNotes];
	// Notify delegate of deactivation of the pin note tools
	[delegate pinNoteToolsDeactivated];
}

/**
 * Display the details of the given pin note.
 *
 * @param pinNote      the pin note of which to display details
 * @param theDelegate  the delegate handling pin note events
 */
- (void)displayPinNote:(AddressAnnotation*)pinNote 
			  delegate:(id<PinNoteManagerDelegate>)theDelegate {
	[[PinNoteViewer sharedPinNoteViewer] displayPinNote:pinNote 
											   delegate:self];
}

/**
 * Helper method to enable relocation of a pin note on the map.
 */
- (void)activateRelocationMode {
	[self activatePlacePinNew:NO];
	relocationModeEnabled = YES;
	
	// Create the relocation toolbar buttons
	UIBarButtonItem* cancelButton;
	cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
																 target:self 
																 action:@selector(handleRelocationCancel)];
	UIBarButtonItem* doneButton;
	doneButton = [[UIBarButtonItem alloc] initWithTitle:@"Done Relocation" 
												  style:UIBarButtonItemStyleDone
												 target:self 
												 action:@selector(handleRelocationDone)];
	UIBarButtonItem* spacer;
	spacer = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
														   target:nil
														   action:nil];
	
	// Add the buttons to the relocation toolbar
	NSArray* buttons = [NSArray arrayWithObjects:cancelButton, spacer, doneButton, nil];
	[relocationToolbar setItems:buttons animated:NO];
	
	[[delegate getViewController].view addSubview:relocationToolbar];
	
	// Animate the relocation toolbar into visibility
	[UIView beginAnimations:nil context:@"relocationToolbar"];
	[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
	[UIView setAnimationDuration:0.2];
	[relocationToolbar setFrame:CGRectMake(0, VIEW_HEIGHT-44, VIEW_WIDTH, 44)];
	[UIView commitAnimations];
	
	[cancelButton release];
	[doneButton release];
	[spacer release];
}

/**
 * Helper method to disable relocation of a pin note on the map.
 */
- (void)deactivateRelocationMode {
	[self deactivatePlacePin];
	relocationModeEnabled = NO;
	
	// Animate the relocation toolbar out of visibility
	[UIView beginAnimations:nil context:@"relocationToolbar"];
	[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
	[UIView setAnimationDuration:0.3];
	[relocationToolbar setFrame:CGRectMake(-VIEW_WIDTH, VIEW_HEIGHT-44, VIEW_WIDTH, 44)];
	[UIView commitAnimations];
}

/**
 * Show all the pin notes.
 */
- (void)showAllPins {
	[delegate showAllPinNotes];
}

/**
 * Activate the add new pin mode.
 */
- (void)activateAddMode {
	[[PinNoteViewer sharedPinNoteViewer] displayWithDelegate:self 
												isNewPinNote:YES];
}

/**
 * Activate the edit newly added pin mode.
 */
- (void)activateEditMode {
	[[PinNoteViewer sharedPinNoteViewer] displayWithDelegate:self 
												isNewPinNote:YES];
}

/**
 * Handle the request to cancel a relocation.
 */
- (void)handleRelocationCancel {
	[delegate toggleVisibilityOfPinNote:currentPinNote];
	[delegate removePinNotes];
	[self deactivateRelocationMode];
	[[PinNoteViewer sharedPinNoteViewer] displayPinNote:currentPinNote 
											   delegate:self];
}

/**
 * Handle the request to complete a relocation.
 */
- (void)handleRelocationDone {
	if (newPinLocation.x != 0 && newPinLocation.y != 0) {
		[delegate relocatePinNote:currentPinNote 
						withCoord:newPinLocation];
		//[delegate savePinNotes];
		[delegate toggleVisibilityOfPinNote:currentPinNote];
	}
	[self handleRelocationCancel];
}

/**
 * Respond to a touch event at the given point.
 *
 * @param touchPoint  the point at which a touch event was triggered
 * @see               TouchableWindowDelegate
 */
- (void)touchedAtPoint:(CGPoint)touchPoint {
	CGRect touchableFrame = CGRectMake(0, 0, VIEW_WIDTH, VIEW_HEIGHT-44);
	if (!CGRectContainsPoint(touchableFrame, touchPoint)) {
		return;
	}
	
	if (placePinModeEnabled) {
		if (!currentPinNote) {
			newPinLocation = touchPoint;
			[delegate removePinNotes];
			[delegate addPinNoteWithCoord:touchPoint
									title:self.pinTitle
							  description:self.pinDesc];
			[GraphicsUtilities changePrompt:@"Tap to readjust position of pin."];
		} else {
			newPinLocation = touchPoint;
			[delegate removePinNotes];
			[delegate addPinNoteWithCoord:newPinLocation
									title:self.pinTitle
							  description:self.pinDesc];
		}
	}
}

/**
 * Get the navigation controller on which to push the pin note viewer.
 *
 * @return  the navigation controller on which to push the pin note viewer
 * @see     PinNoteViewerDelegate
 */
- (UINavigationController*)getNavController {
	return [delegate getViewController].navigationController;
}

/**
 * Handle a request to save a given pin note.
 *
 * @param pinNote  the pin note to save
 * @see            PinNoteViewerDelegate
 */
- (void)requestSavePinNote:(AddressAnnotation*)pinNote {
	[delegate savePinNote:pinNote];
}

/**
 * Handle a request to relocate a given pin note.
 *
 * @param pinNote  the pin note to relocate
 * @see            PinNoteViewerDelegate
 */
- (void)requestRelocatePinNote:(AddressAnnotation*)pinNote {
	//[self activatePlacePinNew:NO];
	currentPinNote = pinNote;
	newPinLocation = CGPointMake(0, 0);
	[self activateRelocationMode];
	[delegate toggleVisibilityOfPinNote:currentPinNote];
}

/**
 * Delete the given persistent pin note.
 *
 * @param pinNote  the pin note to delete
 * @see            PinNoteViewerDelegate
 */
- (void)requestDeletePinNote:(AddressAnnotation*)pinNote {
	[delegate deletePinNote:pinNote];
}

/**
 * Handle notification for completion of entering details 
 * for a new pin note.
 *
 * @param title  title of the new pin note
 * @param notes  notes for the new pin note
 * @see          PinNoteViewerDelegate
 */
- (void)handleNewPinNoteWithTitle:(NSString*)title 
							notes:(NSString*)notes {
	self.pinTitle = title;
	self.pinDesc = notes;
	addButton.title = @"Edit Pin Details";
	addButton.action = @selector(activateEditMode);
	[self activatePlacePinNew:YES];
}

/**
 * Handle notification for completion of editing details 
 * for a newly added pin note.
 *
 * @param title  title of the new pin note
 * @param notes  notes for the new pin note
 * @see          PinNoteViewerDelegate
 */
- (void)handleEditedPinNoteWithTitle:(NSString*)title 
							   notes:(NSString*)notes {
	self.pinTitle = title;
	self.pinDesc = notes;
	placePinModeEnabled = YES;
	
	//[delegate refreshPinNotes];
	[delegate removePinNotes];
	NSLog(@"%f %f", newPinLocation.x, newPinLocation.y);
	[delegate addPinNoteWithCoord:newPinLocation
							title:self.pinTitle
					  description:self.pinDesc];
}

/**
 * Deallocate the pin note manager.
 */
- (void)dealloc {
	if (pinTitle) {
		[pinTitle release], pinTitle = nil;
	}
	if (pinDesc) {
		[pinDesc release], pinDesc = nil;
	}
	
	[addButton release], addButton = nil;
	delegate = nil;
	[toolbar release], toolbar = nil;
	[relocationToolbar release], relocationToolbar = nil;
	[sharedPinNoteManager release], sharedPinNoteManager = nil;
	[super dealloc];
}

@end